﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;

namespace Uniriotec.DC.CoordDist.Centralizada
{
    public class Coordinator
    {
        private int NUM_PROCESS = 0; // number of workers


        private void Debug(string str)
        {
            Console.WriteLine("Coordinator: " + str);
        }

        private Queue<int> requestQueue = new Queue<int>();
        private Dictionary<int, BufferedWriter<NetworkStream>> connections = new Dictionary<int, BufferedWriter<NetworkStream>>();
        private int processInCritical = -1;

        public void StartProcesses(int num) 
        {
            int port = 5200;

            for (int i = 1; i < num + 1; i++) 
            {
                StartProcessParamaters parameters = new StartProcessParamaters(i == 1, i, this, port);
                Process proc = new Process();
                Thread a = new Thread(new ParameterizedThreadStart(proc.Start));
                a.Start(parameters);

                Socket connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                connection.Connect(IPHelper.GetIP("localhost"), port);
                
                connections.Add(i, new BufferedWriter<NetworkStream>(connection));
                port++;
            }

        }

        public void Release(int process) 
        {
            Debug("Process " + process + " released lock");
            processInCritical = -1;
            GiveAccess();
        }

        private void GiveAccess()
        {
            if (processInCritical == -1 && requestQueue.Count > 0)
            {
                int proc = requestQueue.Dequeue();
                processInCritical = proc;

                Debug("Process " + proc + " was given Access");

                connections[proc].WriteLine("Liberated");
                connections[proc].Flush();
            }
            else 
            {
                Debug("Queue is EMPTY");
            }
        }

        public void RequestAccess(int process) 
        {
            requestQueue.Enqueue(process);

            Debug("Process " + process + " Requested Access");

            string queuedItems = String.Empty;
            foreach (int i in requestQueue)
            {
                queuedItems += Convert.ToString(i) + ",";
            }
            
            Debug("Queue " + queuedItems.Substring(0, queuedItems.Length - 1));

            if (processInCritical == -1)
                GiveAccess();
        }

    }
}
